#define GPFSEL1		0x20200004U
#define GPCLR0		0x20200028U
#define GPSET0		0x2020001CU

#define ARM_TIMER_LOAD		0x2000B400U
#define ARM_TIMER_VALUE		0x2000B404U	// READ ONLY
#define ARM_TIMER_CONTROL	0x2000B408U
#define ARM_TIMER_IRQ_ACK	0x2000B40CU	// WRITE ONLY
#define ARM_TIMER_RAW_IRQ	0x2000B410U // READ ONLY
#define ARM_TIMER_MASK_IRQ	0x2000B414U	// READ ONLY
#define ARM_TIMER_RELOAD	0x2000B418U
#define ARM_TIMER_PREDIV	0x2000B41CU
#define ARM_TIMER_FRC		0x2000B420U


extern void Set32(unsigned int addr, unsigned int value);
extern unsigned int Get32(unsigned int addr);


/**************************************************
 * Gestion de la LED
 **************************************************/

unsigned int ledStatus;

void TurnLedOn(void)
{
	// On allume la led
	unsigned int *gpclr0_ptr = ((unsigned int*)GPCLR0);
	*gpclr0_ptr = *gpclr0_ptr | 0x10000U;
	ledStatus = 0U;
}

void TurnLedOff(void)
{
	// On éteint la led
	unsigned int *gpclr0_ptr = ((unsigned int*)GPSET0);
	*gpclr0_ptr = *gpclr0_ptr | 0x10000U;
	ledStatus = 1U;
}

void SwitchLed(void)
{
	if ((ledStatus & 1U) == 0U)
	{
		TurnLedOff();
	}
	else
	{
		TurnLedOn();
	}
}

void InitLed(void)
{
	// On active la fonction du 1 du pin 16 du GPIO
	unsigned int *gpfsel1_ptr = ((unsigned int*)GPFSEL1);
	*gpfsel1_ptr = *gpfsel1_ptr | 0x40000U;
	TurnLedOff();
}


/******************************************************
 * Attente active
 ******************************************************/
void ActiveWait(unsigned int timeToWait)
{
	// On reset le timer ARM
	Set32(ARM_TIMER_CONTROL, 0x3E0000U);
	
	// On charge le timer
	Set32(ARM_TIMER_LOAD, timeToWait);
	
	// On clear les IRQ
	Set32(ARM_TIMER_IRQ_ACK, 0U);

	// On lance le timer, sans IT (attente active)
	Set32(ARM_TIMER_CONTROL, 0x3E0282U);

	while ((Get32(ARM_TIMER_RAW_IRQ) & 1U) == 0U)
	{
		// On attend
	}

	Set32(ARM_TIMER_IRQ_ACK, 0U);
}


/*****************************************************
* Affiche la taille d'un type par clignotement.
* n  octets = n flashs
* *****************************************************/
void FlashSize(unsigned int size)
{
	unsigned int i;

	TurnLedOff();

	for (i = 0U; i < size; i++)
	{
		TurnLedOn();
		ActiveWait(500000U);
		TurnLedOff();
		ActiveWait(500000U);
	}
}


/*****************************************************
 * Fonction kmain
 *****************************************************/
int kmain(void) __attribute__((section(".init")));
int kmain(void)
{
	InitLed();

	FlashSize(sizeof(char));
	ActiveWait(5000000U);

	FlashSize(sizeof(short));
	ActiveWait(5000000U);

	FlashSize(sizeof(short int));
	ActiveWait(5000000U);

	FlashSize(sizeof(int));
	ActiveWait(5000000U);

	FlashSize(sizeof(long));
	ActiveWait(5000000U);

	FlashSize(sizeof(long int));
	ActiveWait(5000000U);

	FlashSize(sizeof(long long));
	ActiveWait(5000000U);

	FlashSize(sizeof(long long int));
	ActiveWait(5000000U);

	for ( ;; )
	{
		// RAF
	}

	return 0;
}
